package cn.mianshiyi.braumclient.monitor;


import cn.mianshiyi.braumclient.common.Constant;
import cn.mianshiyi.braumclient.utils.EasyStringUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.PostConstruct;
import java.util.Random;

/**
 * @author shangqing.liu
 */
public class MonitorStart {

    private static final Logger LOGGER = LoggerFactory.getLogger(MonitorStart.class);

    private static String url;

    @Value("${spring.easy.limiter.monitor.url:#{null}}")
    public void setUrl(String url) {
        this.url = url;
    }

    @PostConstruct
    void startNetty() {
        if (EasyStringUtil.isEmpty(url)) {
            return;
        }
        new Thread(() -> {
            //初始化配置文件
            try {
                start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

    public static synchronized void reConnect() {
        if (LOGGER.isWarnEnabled()) {
            LOGGER.warn("monitor channel reConnect");
        }
        if (EasyStringUtil.isEmpty(url)) {
            return;
        }
        if (MonitorContext.CHANNEL.isActive()) {
            return;
        }
        new Thread(() -> {
            //初始化配置文件
            try {
                Thread.sleep(5000);
                if (MonitorContext.CHANNEL != null && !MonitorContext.CHANNEL.isActive() && !MonitorContext.CHANNEL.isRegistered()) {
                    MonitorContext.CHANNEL.close();
                }
                start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

    public static void start() throws Exception {
        //客户端需要一个事件循环组就可以
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            //创建客户端的启动对象 bootstrap ，不是 serverBootStrap
            Bootstrap bootstrap = new Bootstrap();
            //设置相关参数
            bootstrap.group(group) //设置线程组
                    .channel(NioSocketChannel.class) //设置客户端通道的实现数 （反射）
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
                            ch.pipeline().addLast(new StringDecoder());
                            ch.pipeline().addLast(new NettyClientHandler()); //加入自己的处理器
                        }
                    });
            //连接服务器
            for (int i = 0; i < 3; i++) {
                String serverUrl = selectServer(url);
                try {
                    String[] split = serverUrl.split(Constant.SPIT_MAO);
                    ChannelFuture channelFuture = bootstrap.connect(split[0], Integer.parseInt(split[1])).sync();
                    MonitorContext.CHANNEL = channelFuture.channel();
                    LOGGER.info("easy limiter monitor client ready is ok,server ip:{}", serverUrl);
                    channelFuture.channel().closeFuture().sync();
                    break;
                } catch (Exception e) {
                    LOGGER.error("连接失败,ip:{}", serverUrl, e);
                }
            }
            //对关闭通道进行监听
        } finally {
            group.shutdownGracefully();
        }
    }

    /**
     * 随机选择一台服务端
     * @param url url
     * @return url
     */
    private static String selectServer(String url) {
        if (url.contains(Constant.SPIT_FEN)) {
            String[] urlArray = url.split(Constant.SPIT_FEN);
            int randomInt = new Random().nextInt(urlArray.length);
            return urlArray[randomInt];
        } else {
            return url;
        }
    }

}
